#include "Servidor.h"
#include "MotorJuegoFactory.h"
#include "MotorJuegoServicio.h"
#include "MundoServicio.h"
#include "PartidaServicio.h"

using namespace TP::Comunicacion;

Servidor::Servidor(const string& pPuerto, const string& pRutaDirectorioMundos) {
	// Se inicia  la conexion.
	this->_conexion = new Conexion(pPuerto, this);

	// Se inicia el motor de juego.
	MotorJuegoFactory factory;
	this->_relojJuego = new Reloj(1); // @todo: ajustar los ticks del reloj
	this->_motorJuego = factory.crear(this->_relojJuego);

	// Instancio los servicios.

	// Instancio y registro el servicio Mundo.
	MundoServicio* mundoSrv = (MundoServicio*) new MundoServicio(
			pRutaDirectorioMundos);
	mundoSrv->iniciar();
	this->_servicios.push_back(mundoSrv);

	// Instancio y registro el servicio de Mortor de juego.
	MotorJuegoServicio* motorJuegoSrv = (MotorJuegoServicio*)
			new MotorJuegoServicio();
	motorJuegoSrv->setMotorJuego(this->_motorJuego);
	this->_servicios.push_back(motorJuegoSrv);

	// Instancio y registro el servicio de partidas.
	PartidaServicio* partidaSrv = (PartidaServicio*) new PartidaServicio();
	partidaSrv->setMotorJuego(this->_motorJuego);
	partidaSrv->setMundoServicio(mundoSrv);
	partidaSrv->iniciar();
	this->_servicios.push_back(partidaSrv);
}

Servidor::~Servidor() {
	// Doy de baja la conexion.
	if (this->_conexion)
		delete this->_conexion;

	// Doy de baja los servicios.
	for (int cur = 0; cur < this->_servicios.size(); cur++) {
		this->_servicios[cur]->finalizar();
		delete this->_servicios[cur];
	}
	this->_servicios.clear();
	delete this->_motorJuego;
	delete this->_relojJuego;
}

void Servidor::Iniciar() throw (Excepcion&) {
	try {
		this->_conexion->Iniciar();
		this->_relojJuego->Iniciar();
	}
	catch (Excepcion& pEx) {
		pEx.expandirMensaje("No se puede iniciar el sevidor.");
		throw;
	}
}

void Servidor::Finalizar() throw (Excepcion&) {
	try {
		this->_relojJuego->Finalizar();

		// Doy de baja las sesiones activas.
		for (vector<Sesion*>::size_type cur = 0; cur < 
				this->_sesiones.size(); cur++) {
			try {
				this->_sesiones[cur]->Finalizar();
			}
			catch (Excepcion& pEx) {
				std::cerr << pEx.what() << endl;
			}
			delete this->_sesiones[cur];
		}
		this->_sesiones.clear();
		this->_conexion->Finalizar();
	}
	catch (Excepcion& pEx) {
		pEx.expandirMensaje("No se puede finializar el sevidor.");
		throw;
	}
}

void Servidor::eventoNuevaSesion(IEnviante* pEnviante, void* pArg) {
	Sesion* sesion = (Sesion*)pArg;

	try {
		if (sesion) {
			// Se configuran los manejadores de mensaje de la sesion.
			sesion->agregarManejadorSesionEvento(this);

			for (int cur = 0; cur < this->_servicios.size(); cur++)
				sesion->agregarMensajeEntranteManejador((
						IMensajeEntranteManejador*)this->_servicios[cur]);

			// Se debe iniciar la escucha de mensajes de la sesion.
			sesion->Iniciar();

			// Se debe registrar la sesion en la lista de sesiones del servidor.
			this->_sesiones.push_back(sesion);
		}
	}
	catch (Excepcion& pEx) {
		std::cout << "No se puede manejar la nueva sesion.  " << 
				pEx.what() << endl;
	}
}

void Servidor::eventoErrorComunicacion(IEnviante* pEnviante,
		const string& pMensaje) {
	cerr << pMensaje << endl;
}

void Servidor::eventoConexionFinalizada(IEnviante* pEnviante,
		const string& pMensaje) {
	cerr << pMensaje << endl;
}

void Servidor::eventoErrorConexionInexistente(IEnviante* pConexion, 
		const string& pMensaje) {
	cerr << pMensaje << endl;
}